/*
 * windows_serial_port.cpp
 *
 *  Created on: 2010-3-26
 *      Author: Administrator
 */

#include "windows_serial_port.h"

#include <stdio.h>

WindowsSerialPort::WindowsSerialPort():fileHandle(NULL)
{
	this->readTimeout = 1;
	this->writeTimeout = 1;
}
WindowsSerialPort::~WindowsSerialPort()
{
	if(this->fileHandle != NULL)
	{
		CloseHandle(this->fileHandle);
	}
}
bool WindowsSerialPort::exist(char *portName)
{
        HANDLE fileHandle;

        char bufferName[16];
                int portNumber = 1;

                sscanf(portName, "COM%d", &portNumber);

                if(portNumber > 9)
                {
                        sprintf(bufferName, "\\\\.\\COM%d", portNumber);
                }
                else
                {
                        sprintf(bufferName, "COM%d", portNumber);
                }
                fileHandle = CreateFileA(
                                // the name of the port (as a string)
                                // eg. COM1, COM2, COM4
                                bufferName,
                                // must have read AND write access to port
                                GENERIC_READ | GENERIC_WRITE,
                                // sharing mode
                                // ports CANNOT be shared
                                // (hence the 0)
                                0,
                                // security attributes
                                // 0 here means that this file handle cannot be inherited
                                0,
                                // The port MUST exist before-hand
                                // we cannot create serial ports
                                OPEN_EXISTING,
                                // Overlapped/Non-Overlapped Mode.
                                // To use overlapped communication replace 0 with FILE_FLAG_OVERLAPPED
                                0,
                                // HANDLE of a template file
                                // which will supply attributes and permissions.
                                // Not used with port access
                                0);

                if(fileHandle == INVALID_HANDLE_VALUE) {
                        // error handling code here
                        if(GetLastError() == 2)
                        {
                                return false;
                        }
                        else
                        {
                                return true;
                        }
                }
                else {
                        CloseHandle(fileHandle);
                        return true;
                }
}
bool WindowsSerialPort::open(char * portName)
{
	HANDLE fileHandle;

        char bufferName[16];
                int portNumber = 1;

                sscanf(portName, "COM%d", &portNumber);

                if(portNumber > 9)
                {
                        sprintf(bufferName, "\\\\.\\COM%d", portNumber);
                }
                else
                {
                        sprintf(bufferName, "COM%d", portNumber);
                }

        fileHandle = CreateFileA(
			// the name of the port (as a string)
			// eg. COM1, COM2, COM4
                        bufferName,
			// must have read AND write access to port
			GENERIC_READ | GENERIC_WRITE,
			// sharing mode
			// ports CANNOT be shared
			// (hence the 0)
			0,
			// security attributes
			// 0 here means that this file handle cannot be inherited
			0,
			// The port MUST exist before-hand
			// we cannot create serial ports
			OPEN_EXISTING,
			// Overlapped/Non-Overlapped Mode.
			// To use overlapped communication replace 0 with FILE_FLAG_OVERLAPPED
                        0,
			// HANDLE of a template file
			// which will supply attributes and permissions.
			// Not used with port access
			0);

	if(fileHandle == INVALID_HANDLE_VALUE) {
		// error handling code here
		//printf("Error:%d\n", GetLastError());
		return false;
	}
	else {
		this->fileHandle = fileHandle;
		return true;
	}
}

bool WindowsSerialPort::close()
{
        if(this->fileHandle == NULL)
        {
                return true;
        }
	if(!CloseHandle(this->fileHandle))
	{
		return false;
	}
	this->fileHandle = NULL;
	return true;
}

bool WindowsSerialPort::setSettings(int speed, int wordSize, int stopBits, char parity)
{
	char comSetStr[30];
	sprintf(comSetStr, "%d,%c,%d,%d", speed, parity, wordSize, stopBits);
	DCB dcb; // create the dcb
	// first, set every field of the DCB to 0 to make sure there are no invalid values
	FillMemory(&dcb, sizeof(dcb), 0);
	// set the length of the DCB
	dcb.DCBlength = sizeof(dcb);
	// try to build the DCB
        if(!BuildCommDCBA(comSetStr, &dcb))
	{
		return false;
	}
	// set the state of fileHandle to be dcb
	if(!SetCommState(this->fileHandle, &dcb))
	{
		return false;
	}
	// set the buffers to be size 1024 of fileHandle
	if(!SetupComm(this->fileHandle,
			// in queue
			1024,
			// out queue
			1024))
	{
		return false;
	}
	if(!this->setTimeouts(this->readTimeout, this->writeTimeout))
	{
		return false;
	}
	return true;
}
bool WindowsSerialPort::setTimeouts(int readTimeout, int writeTimeout)
{
	COMMTIMEOUTS cmt; // create the object
	this->readTimeout = readTimeout;
	this->writeTimeout = writeTimeout;

        cmt.ReadIntervalTimeout = 1;
        cmt.ReadTotalTimeoutMultiplier = 0;
	cmt.ReadTotalTimeoutConstant = readTimeout;

	cmt.WriteTotalTimeoutConstant = writeTimeout;
        cmt.WriteTotalTimeoutMultiplier = 1;

	if(!SetCommTimeouts(this->fileHandle, &cmt))
	{
		return false;
	}
	return true;
}

int WindowsSerialPort::readBuf(char * buf, int bufSize)
{

	// the amount of the data actually read will be returned in this variable
	DWORD read = 0;
	ReadFile(
			// the HANDLE that we are reading from
			this->fileHandle,
			// a pointer to an array of words that we want to read
			buf,
			// the size of the array of value to be read
			bufSize,
			// the address of a DWORD that the number of words
			// actually read will be stored in
			&read,
			// a pointer to an overlapped_reader struct
			// that is used in overlapped reading. NULL is out case
			NULL);
	return read;
}

int WindowsSerialPort::writeBuf(char * buf, int bufSize)
{
	// the amount of the data actually written will be returned
	// in this variable
	DWORD write = 0;
	WriteFile(
			// the HANDLE that we are writting to
			this->fileHandle,
			// a pointer to an array of words that we want to write
			buf,
			// the size of the array of values to be written
			bufSize,
			// the address of a DWORD that the number of words
			// actuall written will be stored in
			&write,
			// a pointer to an overlapped_writer struct
			// that is used in overlapped writting.
			// NULL in out case
			NULL);
	return write;
}




